package com.decheng.service;

import cn.hutool.core.util.IdUtil;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @Author 孔德成
 * @Slogan 致敬大师，致敬未来的你
 * @date 2021/8/19
 */
@Service
public class PaymentService {
    /**
     * 正常访问，一切OK
     */
    public String paymentInfo_OK(Integer id) {
        return "线程池：" + Thread.currentThread().getName() + " paymentInfo_OK,id: " + id + "     " + "o(￣▽￣)ｄ";
    }

    /**
     * 超时访问，演示服务降级
     * 可以配置的 HystrixProperty 全在 HystrixCommandProperties 抽象类中
     */
    // 设置超时访问，如果该方法3秒种之内没有返回结果，则服务降级，调用 fallbackMethod
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
    public String paymentInfo_TimeOut(Integer id) {
        // TODO 分别演示以下两种情况导致的服务降级
        // 1. 出现异常，导致服务不可用
//        int age = 10/0;
        // 2. 服务超时，导致服务不可用
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "线程池：" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id: " + id + "     " + "o(￣▽￣)ｄ，耗费3秒";
    }

    public String paymentInfo_TimeOutHandler(Integer id) {
        return "调用支付接口超时或异常，当建线程池名字：" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id: " + id;
    }

    /**
     * 演示服务熔断
     * 当每 10s 请求总数达到 20 时，且请求失败次数达到 10 时，熔断电路(open),
     * 然后每5秒钟尝试请求1次(half-open)，如果请求成功，则恢复电路(closed),否则保持熔断电路(open)
     * 断路器状态：
     * closed - 正常请求服务
     * open - 不会请求服务
     * half-open - 部分请求根据规则调用当前服务，如果请求成功且符合规则则认为当前服务恢复正常，关闭熔断
     *
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", commandProperties = {
            // circuitBreakerEnabled 是否启用断路器：确定断路器是否用于跟踪运行状况和短路请求（跳闸）
            // 默认值为 true
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
            // circuitBreakerRequestVolumeThreshold 请求总数阈值：熔断触发的最小个数/10s
            // 默认值为 20
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
            // circuitBreakerSleepWindowInMilliseconds 时间窗：熔断多少毫秒后去尝试请求
            // 默认值为 5000
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "5000"),
            // circuitBreakerErrorThresholdPercentage 错误百分比阈值：失败率达到多少百分比后触发熔断
            // 默认值为 50
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
    })
    public String paymentCircuitBreaker(Integer id) {
        System.out.println("PaymentService.paymentCircuitBreaker id=" + id);
        // 如果 id 小于0 则抛出异常，导致服务不可用
        if (id < 0) {
            throw new RuntimeException("********id不能为负数");
        }
        // id >=0，服务可用
        // 使用 hutool 工具生成唯一 UUID返回
        String serialNumber = IdUtil.randomUUID();
        return Thread.currentThread().getName() + "----调用成功，流水号为：" + serialNumber;

    }

    /**
     * 服务熔断 callbackMethod
     *
     * @param id
     * @return
     */
    public String paymentCircuitBreaker_fallback(Integer id) {
        return "id 不能负数,请稍后再试, /( ㄒ o ㄒ )/~~ id: " + id;
    }

}
